package com.lrkj.payfee.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.lrkj.common.constant.Constants;
import com.lrkj.common.constant.FeeConstants;
import com.lrkj.common.core.domain.entity.SysUser;
import com.lrkj.common.core.domain.model.LoginUser;
import com.lrkj.common.exception.BaseException;
import com.lrkj.common.utils.*;
import com.lrkj.common.utils.uuid.IdUtils;
import com.lrkj.framework.security.MiniContextUtils;
import com.lrkj.framework.utils.NumberUtils;
import com.lrkj.framework.utils.SerialNumUtil;
import com.lrkj.framework.websocket.WebSocketUtil;
import com.lrkj.framework.websocket.entity.WSMessage;
import com.lrkj.payfee.domain.*;
import com.lrkj.payfee.domain.vo.AdueRecordVo;
import com.lrkj.payfee.domain.vo.PayFeeVo;
import com.lrkj.payfee.domain.vo.RoomNormVo;
import com.lrkj.payfee.factory.PayFeeFactory;
import com.lrkj.payfee.mapper.AdvanceReceiptMapper;
import com.lrkj.payfee.mapper.ReceiptMapper;
import com.lrkj.payfee.mapper.RuleCostMapper;
import com.lrkj.payfee.service.*;
import com.lrkj.payfee.vo.BillPaymentVo;
import com.lrkj.payfee.vo.NormChargeVo;
import com.lrkj.property.domain.Community;
import com.lrkj.property.domain.Room;
import com.lrkj.property.service.ICommunityService;
import com.lrkj.property.service.IRoomService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class TollCenterServiceImpl implements ITollCenterService {

    @Autowired
    private IChargeNormService chargeNormService;

    @Autowired
    private IRoomService roomService;

    @Autowired
    private RuleCostMapper ruleCostMapper;
    @Autowired
    private IRuleCostService ruleCostService;

    @Autowired
    private IRoomNormService roomNormService;

    @Autowired
    private PayFeeFactory payFeeFactory;

    @Autowired
    private IReceiptRecordService receiptRecordService;

    @Autowired
    private IReceiptDetailService receiptDetailService;

    @Autowired
    private ReceiptMapper receiptMapper;

    @Autowired
    private IAdvanceReceiptService advanceReceiptService;

    @Autowired
    private IAgainstRecordService againstRecordService;

    @Autowired
    private IModePaymentService modePaymentService;

    @Autowired
    private AdvanceReceiptMapper advanceReceiptMapper;

    @Autowired
    private ICommunityService communityService;

    @Autowired
    private IComputePayFeeLogService computePayFeeLogService;

    @Autowired
    private IPayOrderService payOrderService;


    @Override
    @Transactional
    @Deprecated
    public int createRoomCost(RoomNormVo roomNormVo) {
        List<RoomNorm> updateRoomNorms = new ArrayList<>();
        List<RuleCost> savaRuleCosts = new ArrayList<>();
        //房屋信息
        Room room = roomService.selectRoomById(roomNormVo.getNodeId());
        Community community = communityService.selectCommunityById(room.getCommunityId());
        roomNormVo.getRoomNorms()
                .stream()

                .forEach(norm -> {
                    NormChargeVo eg = new NormChargeVo();
                    eg.setStatus(FeeConstants.room_norm_status_10001);
                    eg.setRoomNormId(norm.getRoomNormId());
                    List<NormChargeVo> roomNorms = roomNormService.selectArrearageRoomNorm(eg);
                    if (null != roomNorms && roomNorms.size() > 0) {
                        Date lastMonthDay = LrkjDateUtil.getLastMonthDay(DateUtils.dateTime(DateUtils.YYYY_MM_DD, norm.getPaymentCycle()));
                        NormChargeVo roomNorm = roomNorms.get(0);
                        List<Map<String, Date>> costCycle = this.getCostCycle(roomNorm, lastMonthDay);
                        if (null != costCycle && costCycle.size() > 0) {
                            costCycle.stream().forEach(map -> {
                                RuleCost ruleCost = this.createRuleCost(roomNorm, map, community);
                                ruleCost.setCostId(IdUtils.simpleUUID());
                                savaRuleCosts.add(ruleCost);
                            });
                            RuleCost lastRuleCost = savaRuleCosts.get(savaRuleCosts.size() - 1);
                            updateRoomNorms.add(this.createUpdateRoomNorm(roomNorm, lastRuleCost));
                        }
                    }
                });
        if (null != savaRuleCosts && savaRuleCosts.size() > 0) {
            ruleCostMapper.doSaveList(savaRuleCosts);
        }
        if (null != updateRoomNorms && updateRoomNorms.size() > 0) {
            roomNormService.updateByBatch(updateRoomNorms);
        }
        return 1;
    }

    /**
     * 通过房屋收费标准ID  和 缴费截止日期 生成动态费用明细
     ***/
    @Override
    public Map<String, Object> singleCreateRoomCost(TollCenter tollCenter) throws ParseException {
        Map<String, Object> fruitMap = new HashMap<>();
        fruitMap.put("code",200);
        List<RuleCost> savaRuleCosts = new ArrayList<>();
        NormChargeVo eg = new NormChargeVo();
        eg.setStatus(FeeConstants.room_norm_status_10001);
        eg.setRoomNormId(tollCenter.getRoomNormId());
        List<NormChargeVo> roomNorms = roomNormService.selectArrearageRoomNorm(eg);
        if (null != roomNorms && roomNorms.size() > 0) {
            NormChargeVo roomNorm = roomNorms.get(0);
            if (StringUtils.isEmpty(roomNorm.getOwnerId())) {
                throw new BaseException("房屋未入住业主");
            }
            List<RuleCost> oldRuleCosts = null;
            if (StringUtils.isNotEmpty(tollCenter.getRuleCostIds())) {
                RuleCost ruleEg = new RuleCost();
                ruleEg.setRuleCostIds(tollCenter.getRuleCostIds());
                ruleEg.setFiscalPeriod( tollCenter.getPaymentCycle());//缴费截止月
                //ruleEg.setPaymentCycle( LrkjDateUtil.getMaxMonthDate(tollCenter.getPaymentCycle()));//缴费截止月
                oldRuleCosts = ruleCostMapper.selectRuleCostList(ruleEg);
                //升序
                Collections.sort(oldRuleCosts, new Comparator<RuleCost>() {
                    @Override
                    public int compare(RuleCost o1, RuleCost o2) {
                        return o1.getFinishTime().compareTo(o2.getFinishTime());
                    }
                });
                if (null != oldRuleCosts && oldRuleCosts.size() > 0) {
                    //重新计算交乞年月
                    roomNorm.setDeliveryTime(oldRuleCosts.get(oldRuleCosts.size() - 1).getFinishTime());
                }
                savaRuleCosts.addAll(oldRuleCosts);
            }
            if(null != savaRuleCosts && savaRuleCosts.size() > 0){
                RuleCost ruleCost = savaRuleCosts.get(savaRuleCosts.size() - 1);
                Date paymentCycle = DateUtils.parseDate(tollCenter.getPaymentCycle());
                if(paymentCycle.getTime() > ruleCost.getFinishTime().getTime() ){
                    fruitMap.put("code",201);
                    fruitMap.put("maxTime",DateUtils.dateTime(ruleCost.getFinishTime()));
                }else{
                    AdueRecordVo bean = adueRecordFactory(savaRuleCosts);
                    bean.setRuleCostIds(tollCenter.getRuleCostIds());
                    bean.setRoomId(roomNorm.getRoomId());
                    bean.setRoomName(roomNorm.getRoomName());
                    bean.setOwnerId(roomNorm.getOwnerId());
                    bean.setOwnerName(roomNorm.getCustomName());
                    bean.setPrices(roomNorm.getPrices());//单价
                    bean.setProjectId(tollCenter.getProjectId());
                    bean.setNormId(tollCenter.getNormId());
                    bean.setRoomNormId(tollCenter.getRoomNormId());//房屋收费标准
                    bean.setChargeId(roomNorm.getChargeId());//费用项目
                    bean.setPaymentCycle(tollCenter.getPaymentCycle());
                    bean.setChargeName(roomNorm.getChargeName());
                    bean.setNormNames(roomNorm.getNormNames());
                    bean.setRuleCostList(savaRuleCosts);
                    bean.setMonthNum(savaRuleCosts.size());
                    fruitMap.put("adueRecord", bean);
                }
            }else{
                fruitMap.put("code",202);
            }
        } else {
            throw new BaseException("此房间未绑定收费标准");
        }
        return fruitMap;
    }


   /* @Override
    public Map<String, Object> singleCreateRoomCost(TollCenter tollCenter) throws ParseException {
        Map<String, Object> fruitMap = new HashMap<>();
        List<RuleCost> savaRuleCosts = new ArrayList<>();
        Date lastMonthDay = LrkjDateUtil.getLastMonthDay(DateUtils.dateTime(DateUtils.YYYY_MM_DD, tollCenter.getPaymentCycle()));
        NormChargeVo eg = new NormChargeVo();
        eg.setStatus(FeeConstants.room_norm_status_10001);
        eg.setRoomNormId(tollCenter.getRoomNormId());
        List<NormChargeVo> roomNorms = roomNormService.selectArrearageRoomNorm(eg);
        if (null != roomNorms && roomNorms.size() > 0) {
            NormChargeVo roomNorm = roomNorms.get(0);
            if (StringUtils.isEmpty(roomNorm.getOwnerId())) {
                throw new BaseException("房屋未入住业主");
            }
            Community community = communityService.selectCommunityById(roomNorm.getCommunityId());
            List<RuleCost> oldRuleCosts = null;
            if (StringUtils.isNotEmpty(tollCenter.getRuleCostIds())) {
                RuleCost ruleEg = new RuleCost();
                ruleEg.setRuleCostIds(tollCenter.getRuleCostIds());
                ruleEg.setFiscalPeriod(tollCenter.getPaymentCycle());//结账账期
                oldRuleCosts = ruleCostMapper.selectRuleCostList(ruleEg);
                //升序
                Collections.sort(oldRuleCosts, new Comparator<RuleCost>() {
                    @Override
                    public int compare(RuleCost o1, RuleCost o2) {
                        return o1.getFinishTime().compareTo(o2.getFinishTime());
                    }
                });
                if (null != oldRuleCosts && oldRuleCosts.size() > 0) {
                    //重新计算交乞年月
                    roomNorm.setDeliveryTime(oldRuleCosts.get(oldRuleCosts.size() - 1).getFinishTime());
                }
                savaRuleCosts.addAll(oldRuleCosts);
            }
            //获取需要生成的费用单费用区间
            //此时根据房屋费用生成方式字段 生成费用单 1：自然周期 2：顺延周期
            String chargeGenerateType = roomNorm.getChargeGenerateType();
            List<Map<String, Date>> costCycle = new ArrayList<Map<String, Date>>();
            //第一张费用单计费开始时间和结束时间
            //第一张费用单判断开始收费时间和当前账期
            String fiscal_period=community.getFiscalPeriod();
            Date begin_Charge_time=roomNorm.getBeginChargeTime();
            *//*int begin_Charge_time_year=LrkjDateUtil.getYear(begin_Charge_time);
            int begin_Charge_time_month=LrkjDateUtil.getMonth(begin_Charge_time);
            String begin_Charge_time_str=begin_Charge_time_year+"-"+begin_Charge_time_month;*//*
            boolean date_boolean=LrkjDateUtil.compareDate(LrkjDateUtil.getFormatTimeString(begin_Charge_time,"yyyy-MM"),fiscal_period,"yyyy-MM");
            //当开始收费时间小于当前账期月份
           *//* if (date_boolean==true){
            //第一张单子补齐开始收费时间到当前账期的数据
                costCycle.add(LrkjDateUtil.costCycleMap(roomNorm.getNextBeginChargeTime(),roomNorm.getNextFinishChargetime()));
            }else{
            //补第一个月的单子
                costCycle.add(LrkjDateUtil.costCycleMap(roomNorm.getNextBeginChargeTime(),roomNorm.getNextFinishChargetime()));
            }*//*
            //入住逻辑改动，此处不需要管开始收费时间和当前账期月份关系，都是补第一笔单子
            costCycle.add(LrkjDateUtil.costCycleMap(roomNorm.getNextBeginChargeTime(),roomNorm.getNextFinishChargetime()));
            if (chargeGenerateType.equals(FeeConstants.charge_generate_type_10)) {
                costCycle.addAll(this.getCostCycle(roomNorm, lastMonthDay));
            } else if (chargeGenerateType.equals(FeeConstants.charge_generate_type_20)) {
                //下一次计费结束时间 + 1天 ，这里是除第一张费用单之后的单子开始时间
                Date chargetime = DateUtil.offsetDay(roomNorm.getNextFinishChargetime(), 1);
                //下一次开始计费时间小于等于缴费截止月
                if (chargetime.getTime() <= lastMonthDay.getTime()) {
                //    Date chargetime=roomNorm.getDeliveryTime();
                    costCycle.addAll(LrkjDateUtil.createCostCyclePostpone(roomNorm.getBeginChargeTime(), chargetime, lastMonthDay));
                }
            }

            if (null != costCycle && costCycle.size() > 0) {
                costCycle.stream().forEach(map -> {
                    RuleCost ruleCost = this.createRuleCost(roomNorm, map,community);
                    ruleCost.setRoomName(roomNorm.getRoomName());
                    ruleCost.setOwnerName(roomNorm.getCustomName());
                    ruleCost.setNormNames(roomNorm.getNormNames());
                    savaRuleCosts.add(ruleCost);
                });
            }
            if (savaRuleCosts==null || savaRuleCosts.size() == 0) {
                throw new BaseException("未查询到欠费记录");
            }

            //升序
            Collections.sort(savaRuleCosts, new Comparator<RuleCost>() {
                @Override
                public int compare(RuleCost o1, RuleCost o2) {
                    return o1.getFinishTime().compareTo(o2.getFinishTime());
                }
            });
            AdueRecordVo bean = adueRecordFactory(savaRuleCosts);
            bean.setRuleCostIds(tollCenter.getRuleCostIds());
            bean.setRoomId(roomNorm.getRoomId());
            bean.setRoomName(roomNorm.getRoomName());
            bean.setOwnerId(roomNorm.getOwnerId());
            bean.setOwnerName(roomNorm.getCustomName());
            bean.setPrices(roomNorm.getPrices());//单价
            bean.setProjectId(tollCenter.getProjectId());
            bean.setNormId(tollCenter.getNormId());
            bean.setRoomNormId(tollCenter.getRoomNormId());//房屋收费标准
            bean.setChargeId(roomNorm.getChargeId());//费用项目
            bean.setPaymentCycle(tollCenter.getPaymentCycle());
            bean.setChargeName(roomNorm.getChargeName());
            bean.setNormNames(roomNorm.getNormNames());
            bean.setRuleCostList(savaRuleCosts);
            bean.setMonthNum(savaRuleCosts.size());
            fruitMap.put("adueRecord", bean);

        } else {
            throw new BaseException("此房间未绑定收费标准");
        }
        return fruitMap;
    }*/

    //费用单合计
    private AdueRecordVo adueRecordFactory(List<RuleCost> ruleCostList) {
        //费用合计
        AdueRecordVo bean = new AdueRecordVo();
        RuleCost ruleCost = ruleCostList.get(0);
        //应收金额
        AtomicReference<BigDecimal> receivableMoney = new AtomicReference<>(new BigDecimal(0));
        //未收金额
        AtomicReference<BigDecimal> amountOwed = new AtomicReference<>(new BigDecimal(0));
        //已收金额
        AtomicReference<BigDecimal> haveMoney = new AtomicReference<>(new BigDecimal(0));
        //优惠金额
        AtomicReference<BigDecimal> specialMoney = new AtomicReference<>(new BigDecimal(0));
        List<String> ruleCostIds = new ArrayList<>();
        ruleCostList.stream().forEach(x -> {
            receivableMoney.set(NumberArithmeticUtils.safeAdd(receivableMoney.get(), x.getAmountOwed()));
            amountOwed.set(NumberArithmeticUtils.safeAdd(amountOwed.get(), x.getAmountOwed()));
            if (StringUtils.isNotEmpty(x.getCostId())) {
                ruleCostIds.add(x.getCostId());
            }
        });
        if (ruleCostIds.size() > 0) {
            bean.setRuleCostIds(Joiner.on(",").join(ruleCostIds));
        }
        bean.setReceivableMoney(receivableMoney.get());
        bean.setAmountAmount(new BigDecimal(0));
        bean.setAmountOwed(amountOwed.get());
        bean.setHaveMoney(haveMoney.get());
        bean.setSpecialMoney(specialMoney.get());
        bean.setBeginTime(ruleCostList.get(0).getBeginTime());
        bean.setFinishTime(ruleCostList.get(ruleCostList.size() - 1).getFinishTime());
        return bean;
    }


    /***
     * 根据收费标准获取费用周期
     * normChargeVo 收费标准/房屋收费标准 vo
     * **/
    @Override
    public List<Map<String, Date>> getCostCycle(NormChargeVo normChargeVo, Date lastMonthDay) {
        //结束计费时间
        Date finishChargetime = normChargeVo.getFinishChargetime();
        //创建费用截止日期
        Date createFinishTime = null;
        //交讫年月
        Date deliveryTime = normChargeVo.getDeliveryTime();
        //如果交讫年月为空,说明是第一次创建费用,则使用计费开始时间
        if (null == deliveryTime) {
            deliveryTime = normChargeVo.getBeginChargeTime();
        }
        //检查是否设置缴费截止日期
        if (null != finishChargetime) {
            //查看计费结束日期(大于缴费截止月,生成费用的结束日期取缴费截止月,反之使用计费结束日期)
            if (finishChargetime.getTime() > lastMonthDay.getTime()) {
                createFinishTime = lastMonthDay;
            } else {
                createFinishTime = finishChargetime;
            }
        } else {
            createFinishTime = lastMonthDay;
        }
        return LrkjDateUtil.createCostCycle(LrkjDateUtil.addDay(deliveryTime, 1), createFinishTime);
    }

    /**
     * 收费单  工厂
     *
     * @param normChargeVo 收费标准|房屋收费标准
     **/
    @Override
    public RuleCost createRuleCost(NormChargeVo normChargeVo, Map<String, Date> map, Community community) {
        RuleCost bean = new RuleCost();
        bean.setProjectId(normChargeVo.getProjectId());//费用类型
        bean.setChargeId(normChargeVo.getChargeId());//费用项目
        bean.setNormId(normChargeVo.getNormId());//收费标准
        bean.setRoomNormId(normChargeVo.getRoomNormId());//房屋收费标准ID
        bean.setCostNo(ruleCostService.getNo(normChargeVo.getCommunityNum() + FeeConstants.rule_cost_key)); // 费用单号
        bean.setDeptId(normChargeVo.getDeptId());
        bean.setRoomId(normChargeVo.getRoomId());
        bean.setOwnerId(normChargeVo.getOwnerId());//业主ID
        //-------------------------------计费时间-------------------------------
        bean.setBeginTime(map.get(LrkjDateUtil.START_TIME));//计费开始时间
        bean.setReceivableTime(map.get(LrkjDateUtil.START_TIME));//收费时间
        bean.setFinishTime(map.get(LrkjDateUtil.END_TIME));//计费结束时间
        //应收金额
        AtomicReference<BigDecimal> theSameMonthFee = new AtomicReference<>(new BigDecimal(0));
        //当前账期
        Date fiscalPeriodDate = DateUtil.parse(LrkjDateUtil.getMaxMonthDate(community.getFiscalPeriod() + "-01"), "yyyy-MM-dd");
        //当前账期大于费用单开始时间 --  费用期间使用当前账期
        if (fiscalPeriodDate.getTime() > bean.getBeginTime().getTime()) {
            //费用期间
            bean.setFiscalPeriod(community.getFiscalPeriod());
        } else {
            bean.setFiscalPeriod(DateUtil.format(bean.getBeginTime(), "yyyy-MM"));
        }
        //应收金额 ---> 需要放在账期下计算费用,因为计算费用的时候需要用到账期
        theSameMonthFee.set(payFeeFactory.computational(bean, normChargeVo));
        bean.setPrices(normChargeVo.getPrices());//单价
        bean.setMoneys(theSameMonthFee.get());//金额
        bean.setReceivableMoney(theSameMonthFee.get());//应收金额
        bean.setHaveMoney(new BigDecimal(0));//已收金额
        bean.setSpecialMoney(new BigDecimal(0));//优惠金额
        bean.setQueenMoney(theSameMonthFee.get());//优惠后金额
        bean.setAmountOwed(theSameMonthFee.get());//欠费金额
        bean.setAmountAmount(new BigDecimal(0));//冲抵金额
        bean.setCostType("");//费用收取类型
        bean.setStatus(FeeConstants.charge_status_10001);//默认未收全
        bean.setAncestors(normChargeVo.getAncestors());//祖级ID  使用房屋收费标准的祖级ID ， 主要是为了左侧组织架构 查询问题
        bean.setRoomArea(normChargeVo.getRoomArea());//使用面积
        bean.setBuildArea(normChargeVo.getBuildArea());//建筑面积
        return bean;
    }


    /**
     * 创建房屋收费标准更新对象
     *
     * @param normChargeVo 房屋收费标准
     */
    @Override
    public RoomNorm createUpdateRoomNorm(NormChargeVo normChargeVo, RuleCost lastRuleCost) {
        RoomNorm roomNorm = new RoomNorm();
        normChargeVo.setNextBeginChargeTime(lastRuleCost.getBeginTime());
        normChargeVo.setNextFinishChargetime(lastRuleCost.getFinishTime());
        PayFeeVo payFeeVo = payFeeFactory.getPayFeeVo(normChargeVo);
        roomNorm.setNextBeginChargeTime(payFeeVo.getBeginTime());
        roomNorm.setNextFinishChargetime(payFeeVo.getFinishTime());
        roomNorm.setReceivableTime(payFeeVo.getReceivableTime());
        roomNorm.setStatus(payFeeVo.getStatus());
        roomNorm.setRoomNormId(normChargeVo.getRoomNormId());
        return roomNorm;
    }

    /**
     * 房屋收费
     ***/
    @Override
    @Transactional
    public String roomCharge(Receipt receipt) {
        //房屋信息
        Room room = this.getRoom(receipt);

        //房屋收费标准
        Map<String, NormChargeVo> roomNormMap = new HashMap<>();

        NormChargeVo eg = new NormChargeVo();
        eg.setStatus(FeeConstants.room_norm_status_10001);
        eg.setRoomId(receipt.getRoomId());
        List<NormChargeVo> roomNorms = roomNormService.selectArrearageRoomNorm(eg);
        roomNorms.stream().forEach(x -> {
            roomNormMap.put(x.getRoomId() + x.getNormId(), x);
        });
        //1、创建收款单
        this.initReceipt(receipt, room);
        //2、计算预收金额
        this.advanceCompute(receipt);
        //3、计算费用单工厂
        this.ruleCostFactory(receipt);
        //4、计算收款明细工厂
        this.receiptDetailFactory(receipt);
        //5、付款方式工厂
        this.modePaymentFactory(receipt);
        //6、新增预存金额
        this.saveAdvanceReceipt(receipt);
        //7、更新房屋收费标准
        this.updateRoomNorm(receipt, roomNormMap);
//        if (receipt.getReceivableMoney().compareTo(BigDecimal.ZERO) == 598) {
//            throw new BaseException("");
//        }
        PayOrder payOrder = this.createPayOrder(receipt, room);
        receipt.setPayOrderId(payOrder.getId());
        int rows = this.receiptMapper.insertReceipt(receipt);

        return receipt.getReceiptId();
        //throw new BaseException("");
    }


    //创建支付订单  这里是虚拟的订单,是为了让小程序能查询到后台缴费的订单
    private PayOrder createPayOrder(Receipt receipt,Room room) {
        PayOrder payOrder = new PayOrder();
        payOrder.setId(IdUtils.simpleUUID());
        payOrder.setRoomId(room.getId());
        payOrder.setSerialNo(SnowFlakeUtils.snowFlakeId()+"");//这里先随机生成两个订单号
        payOrder.setOrderNo(SnowFlakeUtils.snowFlakeId()+"");
        payOrder.setPayMoney(receipt.getBillMoney());
        payOrder.setCreateBy(room.getCustomName());
        payOrder.setCreateTime(receipt.getBillDate());
        payOrder.setOrderType(FeeConstants.ORDER_TYPE_PT);//平台支付
        payOrderService.insertPayOrder(payOrder);
        return payOrder;
    }


    /*
     * 更新房屋收费标准
     * **/
    private void updateRoomNorm(Receipt receipt, Map<String, NormChargeVo> roomNormMap) {
        receipt.getReceiptDetails().stream().forEach(x -> {
            //临时收费项目不更新房屋收费标准
            if (!x.getProjectId().equals(FeeConstants.charge_project_03)) {
                List<RoomNorm> updateRoomNormList = new ArrayList<>();
                if (null != x.getRuleCosts() && x.getRuleCosts().size() > 0) {
                    //升序
                    Collections.sort(x.getRuleCosts(), new Comparator<RuleCost>() {
                        @Override
                        public int compare(RuleCost o1, RuleCost o2) {
                            return o1.getFinishTime().compareTo(o2.getFinishTime());
                        }
                    });

                    String key = x.getRoomId() + x.getNormId();
                    //房屋收费标准
                    NormChargeVo oldRoomNorm = roomNormMap.get(key);
                    RuleCost ruleCost = x.getRuleCosts().get(x.getRuleCosts().size() - 1);
                    //如果是未收全的单子
                    if (ruleCost.getStatus().equals(FeeConstants.charge_status_10001)) {
                        if (x.getRuleCosts().size() > 1) {
                            ruleCost = x.getRuleCosts().get(x.getRuleCosts().size() - 2);
                        } else {
                            ruleCost = null;
                        }
                    }
                    if (null != ruleCost) {
                        oldRoomNorm.setNextBeginChargeTime(ruleCost.getBeginTime());
                        oldRoomNorm.setNextFinishChargetime(ruleCost.getFinishTime());
                        RoomNorm updateBean = new RoomNorm();
                        //暂时   只有常规收费项目  更新下一次计费时间
                        PayFeeVo payFeeVo = payFeeFactory.getPayFeeVo(oldRoomNorm);
                        updateBean.setRoomNormId(oldRoomNorm.getRoomNormId());
                        updateBean.setStatus(payFeeVo.getStatus());
                        if (x.getProjectId().equals(FeeConstants.charge_project_01)) {
                            updateBean.setNextBeginChargeTime(payFeeVo.getBeginTime());
                            updateBean.setNextFinishChargetime(payFeeVo.getFinishTime());
                            updateBean.setReceivableTime(payFeeVo.getReceivableTime());
                        }
                        //交讫年月
                        updateBean.setDeliveryTime(x.getRuleCosts().get(x.getRuleCosts().size() - 1).getFinishTime());
                        updateRoomNormList.add(updateBean);
                        roomNormService.updateByBatch(updateRoomNormList);
                    }
                }
            }
        });

    }


    //获取房屋信息
    private Room getRoom(Receipt receipt) {
        Room room = null;
        if (StringUtils.isNotEmpty(receipt.getRoomId())) {
            String[] split = receipt.getRoomId().split(",");
            room = roomService.selectRoomById(split[0]);
        }
        return room;
    }

    //获取房屋收费标准集合
    private Map<String, RoomNorm> getRoomNormMap(Receipt receipt) {
        //当前房间绑定房屋收费标准
        List<RoomNorm> roomNorms = roomNormService.selectRoomNormByIds(receipt.getRoomId());
        Map<String, RoomNorm> roomNormMap = new HashMap<>();
        roomNorms.stream().forEach(x -> {
            String key = x.getRoomId() + x.getNormId();
            roomNormMap.put(key, x);
        });
        return roomNormMap;
    }

    //新增预存金额
    private void saveAdvanceReceipt(Receipt receipt) {
        if (null != receipt.getTransferAmount() && receipt.getTransferAmount().compareTo(BigDecimal.ZERO) != 0) {
            AdvanceReceipt advanceReceipt = new AdvanceReceipt();
            advanceReceipt.setNo(SerialNumUtil.getNo("YSK"));
            advanceReceipt.setBillMoney(receipt.getTransferAmount());//转存金额
            advanceReceipt.setBillTime(DateUtils.getNowDate());
            advanceReceipt.setOwnerId(receipt.getOwnerId());
            advanceReceipt.setRoomId(receipt.getRoomId());
            advanceReceipt.setMadvanceReceiptId(IdUtils.simpleUUID());
            advanceReceipt.setCreateBy(SecurityUtils.getUsername());
            advanceReceipt.setCreateTime(DateUtils.getNowDate());
            advanceReceipt.setAmountRemaining(receipt.getTransferAmount());
            advanceReceipt.setStatus(FeeConstants.advance_receipt_status_10001);
            advanceReceipt.setBusinessId(receipt.getReceiptId());
            advanceReceipt.setBusinessType(FeeConstants.BUSINESS_TYPE_RECEIPT);
            advanceReceipt.setBusinessNo(receipt.getNo());
            advanceReceiptMapper.insertAdvanceReceipt(advanceReceipt);
        }
    }


    //付款方式工厂
    private void modePaymentFactory(Receipt receipt) {
        List<ModePayment> savaModePayments = new ArrayList<>();
        if (null != receipt.getModePayments() && receipt.getModePayments().size() > 0) {
            receipt.getModePayments().stream().forEach(x -> {
                ModePayment modePayment = new ModePayment();
                modePayment.setModePaymentId(IdUtils.simpleUUID());
                modePayment.setBillMoney(x.getBillMoney());
                modePayment.setCollectionMethod(x.getCollectionMethod());
                modePayment.setReceiptId(receipt.getReceiptId());
                savaModePayments.add(modePayment);
            });
            modePaymentService.doSaveList(savaModePayments);
        }
    }


    /***
     * 预收计算
     *
     *
     * ***/
    public void advanceCompute(Receipt receipt) {
        //预收金额使用情况,需要计算出来
        //收款单---预收余额
        AtomicReference<BigDecimal> preMoney = new AtomicReference<>(receipt.getPreMoney());

        //查看是否使用预收金额,没有的话不继续进行逻辑处理
        if (preMoney.get().compareTo(BigDecimal.ZERO) > 0) {

            //冲抵金额
            AtomicReference<BigDecimal> amountAmount = new AtomicReference<>(new BigDecimal(0));
            //预收使用总金额
            AtomicReference<BigDecimal> applyAdvan = new AtomicReference<>(new BigDecimal(0));
            for (ReceiptDetail detail : receipt.getReceiptDetails()) {
                if (!FeeConstants.ysxm.equals(detail.getProjectId())) {
                    //预收金额-实收金额=预收剩余金额
                    amountAmount.set(NumberArithmeticUtils.safeSubtract(false, preMoney.get(), detail.getBillMoney()));
                    if (amountAmount.get().compareTo(BigDecimal.ZERO) >= 0) {
                        //预收使用总金额= 预收使用总金额+实收金额
                        applyAdvan.set(NumberArithmeticUtils.safeAdd(applyAdvan.get(), detail.getBillMoney()));
                    } else {
                        //(100-110)= -10
                        //这个时候amountAmount是负数,做加法
                        applyAdvan.set(NumberArithmeticUtils.safeAdd(applyAdvan.get(), preMoney.get()));
                        break;
                    }
                }
            }

            //查询预收余额
            AdvanceReceipt eg = new AdvanceReceipt();
            eg.setRoomId(receipt.getRoomId());
            eg.getParams().put("statusIN", "10001,10002");//查询未使用和已经使用的
            List<AdvanceReceipt> advanceReceipts = advanceReceiptService.selectAdvanceReceiptList(eg);

            List<AdvanceReceipt> updateAdvanceReceipts = new ArrayList<>();

            BigDecimal amountRemaining = new BigDecimal(0);
            for (AdvanceReceipt advance : advanceReceipts) {
                BigDecimal oldRemaining = advance.getAmountRemaining();
                //剩余预收余额 - 扣款金额
                amountRemaining = NumberArithmeticUtils.safeSubtract(false, oldRemaining, applyAdvan.get());
                if (amountRemaining.compareTo(BigDecimal.ZERO) > 0) {
                    //如果等于正数,说明单条预收金额  已经足够抵扣需要支付的金额,直接跳出
                    advance.setAmountRemaining(amountRemaining);
                    updateAdvanceReceipts.add(advance);
                    advance.setStatus(FeeConstants.advance_receipt_status_10002);//部分使用
                    againstRecordService.createAgainstRecord(advance.getMadvanceReceiptId(), receipt.getReceiptId(), "收款单冲抵", receipt.getNo(), applyAdvan.get());
                    break;
                } else {
                    advance.setAmountRemaining(new BigDecimal(0));
                    advance.setStatus(FeeConstants.advance_receipt_status_10003);//已使用
                    updateAdvanceReceipts.add(advance);
                    againstRecordService.createAgainstRecord(advance.getMadvanceReceiptId(), receipt.getReceiptId(), "收款单冲抵", receipt.getNo(), oldRemaining);
                }
            }
            advanceReceiptService.updateByBatch(updateAdvanceReceipts);
        }
    }


    //创建收款单
    private void initReceipt(Receipt receipt, Room room) {
        //查看找零金额大于零 实收金额=实收金额-找零金额
        if (receipt.getOddChangeMoney().compareTo(BigDecimal.ZERO) > 0) {
            receipt.setBillMoney(NumberArithmeticUtils.safeSubtract(false, receipt.getBillMoney(), receipt.getOddChangeMoney()));//实收|收到金额
            receipt.setReceivableMoney(receipt.getBillMoney());
        }
        //收款单---检查预收余额
        this.getPreMoney(receipt);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        receipt.setReceiptId(IdUtils.simpleUUID());
        receipt.setNo(this.getNo(FeeConstants.receipt_key));
        receipt.setRoomId(receipt.getRoomId());
        receipt.setOwnerId(room.getOwnerId());
        receipt.setBillDate(DateUtils.getNowDate());
        receipt.setBillUser(loginUser.getUser().getNickName());
        receipt.setBillUserCode(loginUser.getUsername());
        receipt.setAuditStatus(FeeConstants.audit_status_10001);
        receipt.setInvoiceStatus(FeeConstants.invoice_status_10001);
        receipt.setCreateBy(SecurityUtils.getUsername());
        receipt.setCreateTime(DateUtils.getNowDate());
    }

    public String getNo(String key) {
        int nextVal = SerialNumUtil.getInstance().nextInt(key);
        return key + NumberUtils.frontCompWithZore(nextVal, 7);
    }


    private void receiptDetailFactory(Receipt receipt) {
        receipt.setReceivableMoney(new BigDecimal(0));//初始化收款单应收
        receipt.setAmountAmount(new BigDecimal(0));//初始化收款单冲抵金额
        receipt.setBillMoney(new BigDecimal(0));//初始化收款单实收金额
        receipt.setSpecialMoney(new BigDecimal(0));//初始化收款单优惠金额
        List<ReceiptRecord> savaReceiptRecords = new ArrayList<>();
        //收款单---收款明细
        List<ReceiptDetail> receiptDetails = receipt.getReceiptDetails();
        if (null != receiptDetails && receiptDetails.size() > 0) {
            receiptDetails.stream().forEach(detail -> {
                detail.setReceiptDetailId(IdUtils.simpleUUID());//收款单明细ID
                detail.setReceiptId(receipt.getReceiptId());//收款单ID
                detail.setReceivableMoney(new BigDecimal(0));//初始化费用单应收
                detail.setAmountAmount(new BigDecimal(0));//初始化费用单冲抵金额
                detail.setBillMoney(new BigDecimal(0));//初始化费用单实收金额
                detail.setSpecialMoney(new BigDecimal(0));//初始化费用单优惠金额
                detail.setQueenMoney(new BigDecimal(0));//初始化费用单优惠后金额
                List<RuleCost> ruleCosts = detail.getRuleCosts();
                if (null != ruleCosts && ruleCosts.size() > 0) {
                    for (RuleCost costs : ruleCosts) {
                        //应收金额
                        detail.setReceivableMoney(NumberArithmeticUtils.safeAdd(costs.getPaidMoney(), costs.getAmountAmount(), costs.getSpecialMoney(), detail.getReceivableMoney()));
                        //冲抵金额
                        detail.setAmountAmount(NumberArithmeticUtils.safeAdd(costs.getAmountAmount(), detail.getAmountAmount()));
                        //实收金额
                        //BigDecimal billMoney = NumberArithmeticUtils.safeSubtract(false, costs.getPaidMoney(), costs.getAmountAmount(), costs.getSpecialMoney());
                        //detail.setBillMoney(NumberArithmeticUtils.safeAdd(costs.getPaidMoney(), costs.getAmountAmount(),costs.getSpecialMoney()));
                        detail.setBillMoney(NumberArithmeticUtils.safeAdd(costs.getPaidMoney(), detail.getBillMoney()));
                        //优惠金额
                        detail.setSpecialMoney(NumberArithmeticUtils.safeAdd(costs.getSpecialMoney(), detail.getSpecialMoney()));
                        //优惠后金额 实收金额 - 优惠金额
                        BigDecimal queenMoney = NumberArithmeticUtils.safeSubtract(false, costs.getPaidMoney(), costs.getSpecialMoney());
                        detail.setQueenMoney(NumberArithmeticUtils.safeAdd(queenMoney, detail.getQueenMoney()));
                        //退款金额
                        detail.setDrawbackMoney(new BigDecimal(0));
                        //剩余可退金额
                        detail.setRefundAmount(detail.getBillMoney());
                        //收款明细状态 --- 已收款
                        detail.setStatus(FeeConstants.receipt_detail_status_10);
                        //欠费金额是否大于0
                        if (null != costs.getAmountOwed() && costs.getAmountOwed().compareTo(BigDecimal.ZERO) != 0) {
                            //收费明细费用区间结束时间是扣减余额最后一张单子的结束时间
                            detail.setFinishTime(costs.getFinishTime());
                            costs.setStatus(FeeConstants.charge_status_10001); //未收全
                        } else {
                            costs.setStatus(FeeConstants.charge_status_10002); //已收全
                        }
                        costs.setFullReceiptDate(DateUtils.getNowDate());
                        if (StringUtils.isNotEmpty(costs.getCostId())) {
                            ruleCostMapper.updateRuleCost(costs);//更新费用单
                        } else {
                            Room parentBean = roomService.selectRoomById(costs.getRoomId());
                            costs.setAncestors(parentBean.getAncestors() + "," + costs.getRoomId());
                            costs.setDeptId(parentBean.getDeptId());
                            costs.setCostId(IdUtils.simpleUUID());
                            ruleCostMapper.insertRuleCost(costs);//新增费用单
                        }
                        savaReceiptRecords.add(this.createRuleCostDetail(receipt.getReceiptId(), detail.getReceiptDetailId(), costs));
                    }
                }
                //应收金额
                receipt.setReceivableMoney(NumberArithmeticUtils.safeAdd(detail.getReceivableMoney(), receipt.getReceivableMoney()));
                //冲抵金额
                receipt.setAmountAmount(NumberArithmeticUtils.safeAdd(detail.getAmountAmount(), receipt.getAmountAmount()));
                //实收金额
                receipt.setBillMoney(NumberArithmeticUtils.safeAdd(detail.getBillMoney(), receipt.getBillMoney()));
                //优惠金额
                receipt.setSpecialMoney(NumberArithmeticUtils.safeAdd(detail.getSpecialMoney(), receipt.getSpecialMoney()));
            });
            //批量创建收费明细
            this.receiptDetailService.doSaveList(receiptDetails);
            //批量创建费用单 缴费记录
            this.receiptRecordService.doSaveList(savaReceiptRecords);
        }

    }

    //创建费用单收费记录
    private ReceiptRecord createRuleCostDetail(String receiptId, String detailId, RuleCost costs) {
        ReceiptRecord record = new ReceiptRecord();
        record.setReceiptRecordId(IdUtils.simpleUUID());
        record.setReceiptId(receiptId);//收款单ID;
        record.setReceiptDetailId(detailId);//收款明细ID
        record.setCostId(costs.getCostId());//费用单明细ID
        record.setReceivableMoney(costs.getReceivableMoney());//应收金额
        record.setBillMoney(costs.getPaidMoney());//实收金额
        record.setSpecialMoney(costs.getSpecialMoney());//优惠金额
        record.setAmountAmount(costs.getAmountAmount());//冲抵金额
        record.setCreateTime(DateUtils.getNowDate());
        record.setPaymentNote(costs.getPaymentNote());
        record.setAmountOwed(costs.getAmountOwed());//欠费金额
        return record;
    }

    /***
     * 费用单计算工厂
     * 这里有对象引用问题,因为要排序所以重新定义了收款对象,一个用来计算属性  一个用来赋值
     *
     * **/
    private void ruleCostFactory(Receipt receipt) {
        Receipt computeReceipt = (Receipt) receipt.clone();
        //新的收款明细单
        List<ReceiptDetail> newReceiptDetails = new ArrayList<>();
        //收款单---实收金额
        AtomicReference<BigDecimal> billMoney = new AtomicReference<>(computeReceipt.getBillMoney());
        //收款单---预收余额
        AtomicReference<BigDecimal> preMoney = new AtomicReference<>(computeReceipt.getPreMoney());
        //收款单---收款明细
        List<ReceiptDetail> receiptDetails = computeReceipt.getReceiptDetails();

        if (null != receiptDetails && receiptDetails.size() > 0) {
            receiptDetails.stream().forEach(detail -> {
                ReceiptDetail oldDetail = (ReceiptDetail) detail.clone();
                //创建一个新的集合, 存放费用单,   如果少缴的费用不足以支付超过1张以上的费用单,只会存放到最后一个部分缴费的费用单
                List<RuleCost> newRuleCosts = new ArrayList<>();
                List<RuleCost> ruleCosts = detail.getRuleCosts();
                //升序
                Collections.sort(ruleCosts, new Comparator<RuleCost>() {
                    @Override
                    public int compare(RuleCost o1, RuleCost o2) {
                        return o1.getFinishTime().compareTo(o2.getFinishTime());
                    }
                });
                if (null != ruleCosts && ruleCosts.size() > 0) {
                    for (RuleCost costs : ruleCosts) {
                        //扣款顺序  优先使用预收金额
                        //预收金额大于0的
                        if (preMoney.get().compareTo(BigDecimal.ZERO) > 0) {
                            this.preMoneyDeduct(preMoney, billMoney, costs);
                        } else {
                            //预收金额使用完了之后  使用收到金额
                            if (billMoney.get().compareTo(BigDecimal.ZERO) >= 0) {
                                this.billMoneyDeduct(billMoney, costs);
                            } else {
                                //收到金额使用完了,接下来的费用单就不做检查了
                                break;
                            }
                        }
                        newRuleCosts.add(costs);
                    }
                }
                oldDetail.setRuleCosts(newRuleCosts);
                newReceiptDetails.add(oldDetail);
            });
        }
        receipt.setReceiptDetails(newReceiptDetails);
    }

    /***
     * 预收扣款
     *
     * **/
    private void preMoneyDeduct(AtomicReference<BigDecimal> preMoney, AtomicReference<BigDecimal> billMoney, RuleCost ruleCost) {
        //预收金额-费用单实收金额
        BigDecimal newPreMoney = NumberArithmeticUtils.safeSubtract(false, preMoney.get(), ruleCost.getPaidMoney());
        if (newPreMoney.compareTo(BigDecimal.ZERO) >= 0) {
            //费用单欠费金额
            ruleCost.setAmountOwed(new BigDecimal(0));
            //冲抵金额
            ruleCost.setAmountAmount(ruleCost.getPaidMoney()); //冲抵金额
            //已收金额
            ruleCost.setHaveMoney(new BigDecimal(0));
            //实收金额
            ruleCost.setPaidMoney(new BigDecimal(0));
            //因为所有的欠费  都是预收冲抵的  所以已收金额是0
            preMoney.set(newPreMoney);
        } else {
            //冲抵金额== 剩余预收金额+ 自身  有些费用单是欠费的单子  之前已经产生了  冲抵
            ruleCost.setAmountAmount(NumberArithmeticUtils.safeAdd(ruleCost.getAmountAmount(), preMoney.get()));
            //剩余应收 = 实收金额-剩余预收金额(不足以扣减整张费用的费用)
            BigDecimal residueMake = NumberArithmeticUtils.safeSubtract(false, ruleCost.getPaidMoney(), preMoney.get());

            BigDecimal newBillMoney = NumberArithmeticUtils.safeSubtract(false, billMoney.get(), residueMake);
            if (newBillMoney.compareTo(BigDecimal.ZERO) >= 0) {
                //费用单欠费金额
                ruleCost.setAmountOwed(new BigDecimal(0));
                //剩余应收金额
                BigDecimal remainAmount = NumberArithmeticUtils.safeSubtract(false, ruleCost.getPaidMoney(), preMoney.get());
                //已收金额-有可能之前已经收过费用但是没有收全, 已收金额加上实收金额
                ruleCost.setHaveMoney(NumberArithmeticUtils.safeAdd(ruleCost.getHaveMoney(), remainAmount));
                //更新实收金额
                ruleCost.setPaidMoney(remainAmount);
                billMoney.set(newBillMoney);
            } else {
                //费用单欠费金额 = 剩余应收 - 收到金额
                ruleCost.setAmountOwed(NumberArithmeticUtils.safeSubtract(false, residueMake, billMoney.get()));
                //已收金额-有可能之前已经收过费用但是没有收全, 已收金额加上实收金额
                ruleCost.setHaveMoney(NumberArithmeticUtils.safeAdd(ruleCost.getHaveMoney(), billMoney.get()));
                //实收金额
                ruleCost.setPaidMoney(billMoney.get());
                //收到金额使用完了
                billMoney.set(new BigDecimal(0));
            }
            //预收金额不足以抵扣 费用单金额 使用收到金额扣减费用单
            preMoney.set(new BigDecimal(0));
        }
    }

    /***
     * 收到金额扣款
     *
     * **/
    private void billMoneyDeduct(AtomicReference<BigDecimal> billMoney, RuleCost ruleCost) {
        BigDecimal newBillMoney = NumberArithmeticUtils.safeSubtract(false, billMoney.get(), ruleCost.getPaidMoney());
        if (newBillMoney.compareTo(BigDecimal.ZERO) >= 0) {
            //费用单欠费金额
            ruleCost.setAmountOwed(new BigDecimal(0));
            //已收金额-有可能之前已经收过费用但是没有收全, 已收金额加上实收金额
            ruleCost.setHaveMoney(NumberArithmeticUtils.safeAdd(ruleCost.getHaveMoney(), ruleCost.getPaidMoney()));
            billMoney.set(newBillMoney);
        } else {
            //费用单欠费金额 = 实收金额 - 收到金额
            ruleCost.setAmountOwed(NumberArithmeticUtils.safeSubtract(false, ruleCost.getPaidMoney(), billMoney.get()));
            //已收金额-有可能之前已经收过费用但是没有收全, 已收金额加上实收金额
            ruleCost.setHaveMoney(NumberArithmeticUtils.safeAdd(ruleCost.getHaveMoney(), billMoney.get()));
            //实收金额
            ruleCost.setPaidMoney(billMoney.get());
            //收到金额使用完了
            billMoney.set(new BigDecimal(0));
        }
    }

    //获取预余额
    private void getPreMoney(Receipt receipt) {
        List<ReceiptDetail> newReceiptDetails = new ArrayList<>();
        //预收金额
        AtomicReference<BigDecimal> preMoney = new AtomicReference<>(new BigDecimal(0));
        receipt.getReceiptDetails().stream().forEach(x -> {
            //是否有预收金额
            if (StringUtils.isNotEmpty(x.getProjectId()) && x.getProjectId().equals(FeeConstants.ysxm)) {
                if (null != x.getBillMoney() && x.getBillMoney().compareTo(BigDecimal.ZERO) != 0) {
                    //之前多收   把负数转成正数
                    preMoney.set(x.getBillMoney().negate());
                }
            } else {
                newReceiptDetails.add(x);
            }
        });
        receipt.setReceiptDetails(newReceiptDetails);
        receipt.setPreMoney(preMoney.get());
    }


    /***
     *
     * 创建当期未生成的费用单
     *
     * */
    @Override
    @Transactional
    public void createFeeForm(NormChargeVo normChargeVo, SysUser user) {

        //批次号,用来区分是哪一个批次生成的费用单
        String batcheNo = SerialNumUtil.getNo(DateUtils.getDateNumber(), 3);

        Community community = communityService.selectCommunityById(normChargeVo.getCommunityId());
        List<RuleCost> savaRuleCosts = new ArrayList<>();
        List<RoomNorm> updateRoomNorms = new ArrayList<>();
        //1、查询房屋收费标准(常规费用)
        NormChargeVo eg = new NormChargeVo();
        Date fiscalPeriodDate = DateUtil.parse(normChargeVo.getFiscalPeriod() + "-01", "yyyy-MM-dd");
        Date lastMonthDay = LrkjDateUtil.getLastMonthDay(fiscalPeriodDate);
        eg.setStatus(FeeConstants.room_norm_status_10001);
        //eg.getParams().put("deliveryTimeLT", LrkjDateUtil.getFormatTimeString(lastMonthDay, LrkjDateUtil.DATE_FORMATE_STRING_B));
        eg.getParams().put("fiscalPeriod", normChargeVo.getFiscalPeriod());
        eg.getParams().put("notNullOwnerId", "Y");
        eg.getParams().put("projectIdIN", "'01','05'");//常规费用单，租赁费用
        eg.setCommunityId(normChargeVo.getCommunityId());
        eg.setRoomNormIds(normChargeVo.getRoomNormIds());
        List<NormChargeVo> roomNorms = roomNormService.selectArrearageRoomNorm(eg);
        roomNorms.stream().forEach(x -> {
            this.createNormChargeFee(x, lastMonthDay, community, batcheNo, user, savaRuleCosts, updateRoomNorms);
        });
        if (null != savaRuleCosts && savaRuleCosts.size() > 0) {
            ruleCostService.doSaveList(savaRuleCosts);
            //更新收费标准
            if (null != updateRoomNorms && updateRoomNorms.size() > 0) {
                roomNormService.updateByBatch(updateRoomNorms);
            }
        }
        JSONObject msg = new JSONObject();
        msg.put("num", savaRuleCosts.size());
        msg.put("batcheNo", batcheNo);
        //发送websocket
        WebSocketUtil.sendMessageTo(user.getUserName(), WSMessage.getPcWSMessage("CREATE_FEE_FORM", msg.toJSONString(), 0));
    }

    /*
     * 通过收费标准创建费用单
     *
     * 这里参数比较多,是因为之前写的逻辑，现下为了适应 批量计算费用，故此先这样,优化的话 之后在进行
     * **/
    public void createNormChargeFee(NormChargeVo x, Date lastMonthDay, Community community, String batcheNo, SysUser user, List<RuleCost> savaRuleCosts, List<RoomNorm> updateRoomNorms) {
        //交乞年月 -- 为了防止创建费用单对象的时候把交乞年月重新赋值 , 这里先复制下来
        Date deliveryTime = x.getDeliveryTime();
        //下一次开始计费时间如果不为空就赋值给  交乞年月,为了计算费用周期, 处理完之后  在把缴费周期设置为之前的值
        if (null != x.getNextBeginChargeTime()) {
            x.setDeliveryTime(LrkjDateUtil.addDay(x.getNextBeginChargeTime(), -1));
        }
        //获取需要生成的费用单费用区间
        List<Map<String, Date>> costCycle = new ArrayList<>();
        //此时根据房屋费用生成方式字段 生成费用单 1：自然周期 2：顺延周期
        if (x.getChargeGenerateType().equals(FeeConstants.charge_generate_type_10)) {
            costCycle = this.getCostCycle(x, lastMonthDay);
        } else if (x.getChargeGenerateType().equals(FeeConstants.charge_generate_type_20)) {
            costCycle = LrkjDateUtil.createCostCyclePostpone(x.getBeginChargeTime(), x.getNextBeginChargeTime(), lastMonthDay);
        }
        if (null != costCycle && costCycle.size() > 0) {
            costCycle.stream().forEach(map -> {
                RuleCost ruleCost = this.createRuleCost(x, map, community);
                ruleCost.setCostId(IdUtils.simpleUUID());
                ruleCost.setRoomName(x.getRoomName());
                ruleCost.setOwnerName(x.getCustomName());
                ruleCost.setNormNames(x.getNormNames());
                ruleCost.setBatcheNo(batcheNo);
                ruleCost.setCreateBy(user.getNickName());
                ruleCost.setCreateTime(DateUtils.getNowDate());
                savaRuleCosts.add(ruleCost);
            });
            RuleCost lastRuleCost = savaRuleCosts.get(savaRuleCosts.size() - 1);
            RoomNorm updateRoomNorm = this.createUpdateRoomNorm(x, lastRuleCost);
            updateRoomNorm.setDeliveryTime(deliveryTime);
            updateRoomNorms.add(updateRoomNorm);
        }
    }


    /**
     * 计算费用
     **/
    @Override
    public int computePayfee(ComputePayFeeLog computePayFee) {
        try {
            NormChargeVo eg = new NormChargeVo();
            eg.setStatus(FeeConstants.room_norm_status_10001);
            eg.setCommunityId(computePayFee.getCommunityId());
            eg.setFloorId(computePayFee.getFloorId());
            eg.setUnitId(computePayFee.getUnitId());
            eg.setRoomId(computePayFee.getRoomId());
            eg.setNormId(computePayFee.getNormId());
            eg.getParams().put("fiscalPeriod", computePayFee.getPaymentCycle());//计费截至日期
            eg.getParams().put("notNullOwnerId", "Y");//房屋必须是入住状态
            //获取需要计费的费用标准
            List<NormChargeVo> normChargeVos = roomNormService.selectArrearageRoomNorm(eg);
            if (null != normChargeVos && normChargeVos.size() > 0) {
                String id = IdUtils.simpleUUID();
                SysUser user = SecurityUtils.getLoginUser().getUser();

                //新增的收费单列表
                List<RuleCost> savaRuleCosts = new ArrayList<>();
                //更新的收费标准列表
                List<RoomNorm> updateRoomNorms = new ArrayList<>();
                //计费截至月,最大的天数
                Date fiscalPeriodDate = DateUtil.parse(computePayFee.getPaymentCycle() + "-01", "yyyy-MM-dd");
                Date lastMonthDay = LrkjDateUtil.getLastMonthDay(fiscalPeriodDate);
                //小区对象
                Community community = communityService.selectCommunityById(normChargeVos.get(0).getCommunityId());

                normChargeVos.stream().forEach(x -> {
                    this.createNormChargeFee(x, lastMonthDay, community, id, user, savaRuleCosts, updateRoomNorms);
                });

                if (null != savaRuleCosts && savaRuleCosts.size() > 0) {
                    ruleCostService.doSaveList(savaRuleCosts);
                    //更新收费标准
                    if (null != updateRoomNorms && updateRoomNorms.size() > 0) {
                        roomNormService.updateByBatch(updateRoomNorms);
                    }
                }
                computePayFee.setId(id);
                computePayFee.setFeeNum(savaRuleCosts.size());
                computePayFee.setStatus(Constants.SUCCESS);
            }
        } catch (Exception e) {
            computePayFee.setFeeNum(0);
            computePayFee.setStatus(Constants.FAIL);
        }
        computePayFeeLogService.insertComputePayFeeLog(computePayFee);
        return 1;
    }


}
